package com.shxzz.easy12306.services.ticket.service.handler.select;

import cn.hutool.core.collection.CollUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 座位选择工具类
 * <p>
 *     座位布局使用 int[] 表示，数组长度为座位排数，每排座位信息为一个 int 变量，从低位到高位，使用一个 bit 表示对应座位状态，1 代表空闲，0 代表不可用
 * </p>
 * @author shxzz
 * @create 2024-03-07-23:43
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class SeatSelectUtil {

    /**
     * 座位排数最大值
     */
    public static final int SEAT_PER_ROW_MAX = 6;

    /**
     * 模板匹配返回符合条件的座位
     * @param seatLayout 座位布局
     * @param filter 匹配模板，一个 int 变量表示要匹配座位的相对关系，从低位到高位，1 代表需要匹配
     * @return 第一次匹配成功的结果，如果匹配失败是空列表
     */
    public static List<int[]> selectSeatByFilter(int[] seatLayout, int... filter) {
        for (int row = 0; row < seatLayout.length - filter.length + 1; row++) {
            int index = 0;
            while (index < filter.length && (filter[index] & seatLayout[row+index]) == filter[index]) {
                index++;
            }
            if (index != filter.length) continue;

            List<int[]> result = new ArrayList<>();
            for (int i = 0; i < filter.length; i++) {
                for (int j = 0; j < SEAT_PER_ROW_MAX; j++) {
                    if ((filter[i] & (1 << j)) > 0) {
                        result.add(new int[]{row + i, j});
                    }
                }
            }
            return result;
        }
        return new ArrayList<>();
    }

    /**
     * 选择空闲座位，不要求连续
     * @param seatLayout 座位布局
     * @param num 座位数量
     */
    public static List<int[]> noAdjacent(int[] seatLayout, int num) {
        List<int[]> selected = new ArrayList<>(num);
        for (int i = 0; i < seatLayout.length; i++) {
            int filter = 1;
            for (int j = 0; j < SEAT_PER_ROW_MAX; j++) {
                if ((seatLayout[i] & filter) == filter) {
                    selected.add(new int[]{i, j});
                    if (selected.size() == num) return selected;
                }
                filter <<= 1;
            }
        }
        return new ArrayList<>();
    }

    /**
     * 选择连续空闲座位
     * @param seatLayout 座位布局
     * @param num 座位数量
     */
    public static List<int[]> adjacent(int[] seatLayout, int num) {
        int filter = 1;
        filter <<= num;
        filter--;
        for (int i = 0; i < SEAT_PER_ROW_MAX - num + 1; i++) {
            List<int[]> selected = selectSeatByFilter(seatLayout, filter);
            if (CollUtil.isNotEmpty(selected)) return selected;
            filter <<= 1;
        }
        return new ArrayList<>();
    }

    /**
     * 将选择的座位设置为不可用，也就是置 0
     * @param seatLayout 布局
     * @param groupSelect 已选择的座位
     */
    public static void setSelectSeatUnavailable(int[] seatLayout, List<int[]> groupSelect) {
        for(int[] each : groupSelect) {
            int row = each[0];
            int col = each[1];
            seatLayout[row] ^= 1<<col;
        }
    }

    /**
     * 深拷贝座位布局
     */
    public static int[] deepCopySeatLayout(int[] seatLayout) {
        return Arrays.copyOf(seatLayout, seatLayout.length);
    }
}
